package com.sunrise.estoque.bean;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;

import javax.annotation.Resource;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.ComponentSystemEvent;
import javax.servlet.ServletContext;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.xml.bind.JAXBException;

import lombok.Getter;
import lombok.Setter;
import net.sf.jasperreports.engine.JRExporterParameter;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import net.sf.jasperreports.engine.export.JRPdfExporter;

import org.primefaces.event.FileUploadEvent;
import org.springframework.stereotype.Controller;

import com.sunrise.estoque.servico.ManterMovimentacaoEstoqueService;
import com.sunrise.estoque.visao.MovimentacaoEstoqueForm;
import com.sunrise.generico.bean.ManterBean;
import com.sunrise.generico.dataModel.PessoaDataModel;
import com.sunrise.generico.dataModel.ProdutoDataModel;
import com.sunrise.generico.entidade.Filial;
import com.sunrise.generico.entidade.HistoricoMovimentacao;
import com.sunrise.generico.entidade.ModeloNF;
import com.sunrise.generico.entidade.MovimentacaoEstoque;
import com.sunrise.generico.entidade.MovimentacaoProduto;
import com.sunrise.generico.entidade.NaturezaNF;
import com.sunrise.generico.entidade.NotaFiscal;
import com.sunrise.generico.entidade.Pessoa;
import com.sunrise.generico.entidade.Produto;
import com.sunrise.generico.entidade.SerieNF;
import com.sunrise.generico.entidade.Usuario;
import com.sunrise.generico.entidade.iface.EntidadeManter;
import com.sunrise.generico.enums.TipoMovimentacao;
import com.sunrise.generico.enums.TipoPessoaEnum;
import com.sunrise.generico.enums.TipoStatus;
import com.sunrise.generico.nfe.NfeProc;
import com.sunrise.generico.util.ContextUtil;
import com.sunrise.generico.util.FileUtil;
import com.sunrise.generico.util.JAXBUtil;
import com.sunrise.generico.util.MatematicaUtil;
import com.sunrise.generico.util.MessagesUtil;
import com.sunrise.generico.visao.Filtro;

@ManagedBean
@ViewScoped
@Controller
public class ManterMovimentacaoEstoqueBean extends ManterBean<MovimentacaoEstoque> {

	@Resource
	@Getter
	private ManterMovimentacaoEstoqueService movimentancaoService;

	@Getter
	@Setter
	@Resource
	private MovimentacaoEstoqueForm formulario;

	@Resource
	@Getter
	private ManterProdutoBean manterProdutoBean;

	@Override
	public List<MovimentacaoEstoque> iniciarlizarListEntidade() {
		return new ArrayList<MovimentacaoEstoque>();
	}

	@Override
	public void inicializarEntidade() {
		setEntidade(new MovimentacaoEstoque());
		getEntidade().setHistoricosMovimentacao(new ArrayList<HistoricoMovimentacao>());
		getEntidade().setFilial(new Filial());
		getEntidade().setNotaFiscal(new NotaFiscal());
		getEntidade().getNotaFiscal().setSerie(new SerieNF());
		getEntidade().getNotaFiscal().setNatureza(new NaturezaNF());
		getEntidade().getNotaFiscal().setModelo(new ModeloNF());
		getEntidade().setResponsavel(obterUsuarioLogado());
		getEntidade().setMovimentacoesProduto(new ArrayList<MovimentacaoProduto>());
		setFormulario(getMovimentancaoService().carregarFormulario(getFormulario(), obterUsuarioLogado()));
		getFormulario().setSalvo(false);
		getManterProdutoBean().setEntidade(new Produto());
		getManterProdutoBean().getEntidade().setAtivo(Boolean.TRUE);
		inicializarTotais();
	}

	@Override
	public void preRenderList(ComponentSystemEvent event) {
		getFormulario().setFiliais(getMovimentancaoService().listarFiliaisPorUsuario(obterUsuarioLogado()));
		setStatus(Arrays.asList(TipoStatus.values()));
		inicializarEntidade();
		setFiltro(new Filtro());
		setEntidades(getMovimentancaoService().buscarPorFiltros(getFormulario().getFiltroDataMovimentacao(),
				getFormulario().getFiltroNomeProduto(), getFormulario().getFiltroStatusMovimentacao(),
				getFormulario().getFiltroNumeroNota(), getFormulario().getFiltroFilial()));
	}

	@Override
	public void preRenderEdit(ComponentSystemEvent event) {
		setEntidade(getMovimentancaoService().buscarMovimentacaoPorId(getEntidade().getId()));
		carregarNotaFiscalEdit();
		somarValores();
	}

	private void carregarNotaFiscalEdit() {
		if (getEntidade().getNotaFiscal() == null) {
			getEntidade().setNotaFiscal(new NotaFiscal());
			getEntidade().getNotaFiscal().setSerie(new SerieNF());
			getEntidade().getNotaFiscal().setNatureza(new NaturezaNF());
			getEntidade().getNotaFiscal().setModelo(new ModeloNF());
		} else {

			if (getEntidade().getNotaFiscal().getSerie() == null) {
				getEntidade().getNotaFiscal().setSerie(new SerieNF());
			}

			if (getEntidade().getNotaFiscal().getNatureza() == null) {
				getEntidade().getNotaFiscal().setNatureza(new NaturezaNF());
			}

			if (getEntidade().getNotaFiscal().getModelo() == null) {
				getEntidade().getNotaFiscal().setModelo(new ModeloNF());
			}

		}

	}

	@Override
	public void preRenderNew(ComponentSystemEvent event) {
		if (getEntidade() == null) {
			inicializarEntidade();
		}
		getMovimentancaoService().carregarFormulario(getFormulario(), obterUsuarioLogado());
	}

	@Override
	public String salvar() {
		getEntidade().setResponsavel(obterUsuarioLogado());
		getMovimentancaoService().atualizarEstoque(getEntidade());
		return getListar();
	}

	public String cadastrarMovimentacao() {
		getEntidade().setCriador(obterUsuarioLogado());
		getMovimentancaoService().salvarMovimentacao(getEntidade(), getFormulario().isProdutosAlterados());
		return getListar();
	}

	public void validarMovimentacao() {
		getFormulario().setMensagemValidacao(null);
		if(getEntidade().getFilial() == null || getEntidade().getFilial().getId() == null || getEntidade().getFilial().getId() == 0){
			MessagesUtil.addNewInfoMessage(MessagesUtil.getMessageKey("filialInexistente"));
			getFormulario().setSalvo(false);
		}else if (validarListaProdutos()) {
			getFormulario().setSalvo(true);
			getFormulario().setProdutosAlterados(getMovimentancaoService().validarProdutosAlterados(getEntidade()));
		} else {
			getFormulario().setSalvo(false);
		}

	}

	public Boolean validarNotaFiscal() {
		NotaFiscal notaFiscal = null;
		if (getEntidade().getNotaFiscal().getNumero() != null
				&& getEntidade().getNotaFiscal().getSerie().getId() != null) {
			notaFiscal = getMovimentancaoService().buscarNotaFiscalPorNumero(getEntidade().getNotaFiscal().getNumero(),
					getEntidade().getNotaFiscal().getSerie().getId());
		}

		if (notaFiscal != null) {
			MessagesUtil.addNewInfoMessage(MessagesUtil.getMessageKey("notaFiscalExistente"));
			return false;
		}
		return true;
	}

	private boolean validarListaProdutos() {
		if (getEntidade().getMovimentacoesProduto().isEmpty()) {
			MessagesUtil.addNewInfoMessage(MessagesUtil.getMessageKey("movimentacaoSemProduto"));
			return false;
		} else {
			for (MovimentacaoProduto movProd : getEntidade().getMovimentacoesProduto()) {
				if (movProd.getValorProduto() == null) {
					MessagesUtil.addNewInfoMessage(MessagesUtil.getMessageKey("produtoSemPrecoVenda"));
					return false;
				}
				if (movProd.getProduto().getId() == null) {
					getFormulario().setMensagemValidacao(
							MessagesUtil.getMessageKey("produtoSeraInseridoAutomaticamente"));
				}
			}
		}
		return true;
	}

	public List<String> autoCompleteProdutoPorNome(String nome) {
		getFormulario().getProdutoFiltro().setNome(nome);
		getFormulario().setProdutosComplete(
				getMovimentancaoService().buscarProdutoPorNome(getFormulario().getProdutoFiltro().getNome()));
		List<String> listaEntidades = new ArrayList<String>();
		for (EntidadeManter e : getFormulario().getProdutosComplete()) {
			listaEntidades.add(e.getNome());
		}
		return listaEntidades;
	}

	public void buscarProdutosSelecionar() {
		getFormulario().setProdutosSelecionar(
				new ProdutoDataModel(getMovimentancaoService().buscarProdutosPorCodigoNome(
						getFormulario().getProdutoFiltro())));
	}

	public void adicionarProdutos() {
		if (getEntidade().getMovimentacoesProduto() == null) {
			getEntidade().setMovimentacoesProduto(new ArrayList<MovimentacaoProduto>());
		} else if (getFormulario().getProdutosSelecionados() != null) {
			for (Produto produto : getFormulario().getProdutosSelecionados()) {
				boolean existe = false;
				for (MovimentacaoProduto movProd : getEntidade().getMovimentacoesProduto()) {
					if (produto.getId().equals(movProd.getProduto().getId())) {
						existe = true;
						break;
					}
				}
				if (!existe) {
					MovimentacaoProduto novaMP = new MovimentacaoProduto();
					novaMP.setTipoMovimentacao(TipoMovimentacao.ENTRADA);
					novaMP.setQtCom(new BigDecimal(1));
					novaMP.setProduto(produto);
					novaMP.setQtTrib(new BigDecimal(1));
					novaMP.setValorProduto(produto.getCusto());
					novaMP.setUnCom(produto.getUnidade());
					novaMP.setLucro(calcularLucroMovimentacao(novaMP));
					getEntidade().getMovimentacoesProduto().add(novaMP);
				}
			}
		}

		getFormulario().setProdutosSelecionados(null);
		getFormulario().setProdutosSelecionar(new ProdutoDataModel());
		somarValores();

	}

	private BigDecimal calcularLucroMovimentacao(MovimentacaoProduto mov) {
		BigDecimal lucro = mov.getProduto().getPrecoVenda();
		if (lucro == null) {
			lucro = new BigDecimal(0);
		}

		if (mov.getValorFrete() != null) {
			lucro = lucro.subtract(mov.getValorFrete());
		}

		if (mov.getValorProduto() != null) {
			lucro = lucro.subtract(mov.getValorProduto());
		}

		if (mov.getValorSeguro() != null) {
			lucro = lucro.subtract(mov.getValorSeguro());
		}

		if (mov.getValorDespesas() != null) {
			lucro = lucro.subtract(mov.getValorDespesas());
		}

		if (mov.getProduto().getIcms() != null && mov.getProduto().getIcms().getVICMS() != null) {
			lucro = lucro.subtract(mov.getProduto().getIcms().getVICMS());
		} else if (mov.getProduto().getIcms() != null && mov.getProduto().getIcms().getPICMS() != null) {
			mov.getProduto()
					.getIcms()
					.setVICMS(
							MatematicaUtil.calcularValorPercentual(mov.getProduto().getCusto(), mov.getProduto()
									.getIcms().getPICMS()));
			lucro = lucro.subtract(mov.getProduto().getIcms().getVICMS());
		}

		if (mov.getProduto().getIpi() != null && mov.getProduto().getIpi().getValorIpi() != null) {
			lucro = lucro.subtract(mov.getProduto().getIpi().getValorIpi());
		} else if (mov.getProduto().getIpi() != null && mov.getProduto().getIpi().getValorAliq() != null) {
			mov.getProduto()
					.getIpi()
					.setValorIpi(
							MatematicaUtil.calcularValorPercentual(mov.getProduto().getCusto(), mov.getProduto()
									.getIpi().getValorAliq()));
			lucro = lucro.subtract(mov.getProduto().getIpi().getValorIpi());
		}

		return lucro;
	}

	public void removerProdutoEntrada() {
		getEntidade().getMovimentacoesProduto().remove(getFormulario().getMovProdRemover());
		somarValores();
	}

	public void carregarXML(FileUploadEvent event) {
		try {
			Usuario usuarioLogado = obterUsuarioLogado();
			getFormulario().setFile(event.getFile());
			getFormulario().setTabAtiva(0);
			String realPath = ContextUtil.obterRealPath("/");
			File file = new File(realPath + "nfe" + Math.random());
			FileUtil.copiarInputStreamParaArquivo(event.getFile().getInputstream(), file);
			NfeProc nfeProc = JAXBUtil.unmarhNFe(file);
			setFormulario(getMovimentancaoService().carregarFormulario(getFormulario(), usuarioLogado));
			setEntidade(getMovimentancaoService().carregarMovimentacaoEstoqueNFe(nfeProc, usuarioLogado, getFormulario().getConfiguracao()));
			somarValores();

		} catch (IOException e) {
			MessagesUtil.addNewErrorMessage(MessagesUtil.getMessageKey(e.getMessage()),
					MessagesUtil.getMessageKey("detailsCriarArquivo"));
		} catch (JAXBException e) {
			MessagesUtil.addNewErrorMessage(MessagesUtil.getMessageKey(e.getMessage()),
					MessagesUtil.getMessageKey("detailsImportarNFe"));
		}

	}

	public void somarValores() {
		inicializarTotais();
		for (MovimentacaoProduto movProd : getEntidade().getMovimentacoesProduto()) {
			getEntidade().setValorTotal(
					getEntidade().getValorTotal().add(movProd.getValorProduto().multiply(movProd.getQtCom())));
			if (movProd.getValorDesconto() != null) {
				getFormulario().setDescontosTotal(getFormulario().getDescontosTotal().add(movProd.getValorDesconto()));
			}
			if (movProd.getValorDespesas() != null) {
				getFormulario().setDespesasTotal(getFormulario().getDespesasTotal().add(movProd.getValorDespesas()));
			}
			if (movProd.getValorFrete() != null) {
				getFormulario().setFreteTotal(getFormulario().getFreteTotal().add(movProd.getValorFrete()));
			}
			if (movProd.getValorProduto() != null) {
				getFormulario().setValorTotal(getFormulario().getValorTotal().add(movProd.getValorProduto()));
			}
			if (movProd.getQtCom() != null) {
				getFormulario().setUnidadeTotal(getFormulario().getUnidadeTotal().add(movProd.getQtCom()));
			}
			if (movProd.getValorSeguro() != null) {
				getFormulario().setSeguroTotal(getFormulario().getSeguroTotal().add(movProd.getValorSeguro()));
			}
			if (movProd.getProduto().getIcms() != null && movProd.getProduto().getIcms().getVICMS() != null) {
				getFormulario().setIcmsTotal(
						getFormulario().getIcmsTotal().add(movProd.getProduto().getIcms().getVICMS()));
			}
			if (movProd.getProduto().getIpi() != null && movProd.getProduto().getIpi().getValorIpi() != null) {
				getFormulario().setIpiTotal(
						getFormulario().getIpiTotal().add(movProd.getProduto().getIpi().getValorIpi()));
			}
			movProd.setLucro(calcularLucroMovimentacao(movProd));

		}

	}

	private void inicializarTotais() {
		getFormulario().setDespesasTotal(new BigDecimal(0));
		getFormulario().setDescontosTotal(new BigDecimal(0));
		getFormulario().setFreteTotal(new BigDecimal(0));
		getFormulario().setValorTotal(new BigDecimal(0));
		getFormulario().setUnidadeTotal(new BigDecimal(0));
		getFormulario().setIcmsTotal(new BigDecimal(0));
		getFormulario().setIpiTotal(new BigDecimal(0));
		getFormulario().setSeguroTotal(new BigDecimal(0));
		getEntidade().setValorTotal(new BigDecimal(0));

	}

	public void salvarProduto() {
		getMovimentancaoService().salvarProduto(getManterProdutoBean().getEntidade());
		for (MovimentacaoProduto movProd : getEntidade().getMovimentacoesProduto()) {
			if (movProd.getProduto().getCEAN() != null && getManterProdutoBean().getEntidade().getCEAN() != null
					&& movProd.getProduto().getCEAN().equals(getManterProdutoBean().getEntidade().getCEAN())) {
				movProd.setProduto(getManterProdutoBean().getEntidade());
			}
		}
	}

	public String cancelarMovimentacao() {
		getEntidade().setResponsavelCancelar(obterUsuarioLogado());
		getMovimentancaoService().cancelarMovimentacao(getEntidade());
		return getListar();
	}

	public List<String> autoCompleteProdutoNome(String nome) {
		List<Produto> produtos = getMovimentancaoService().buscarProdutosPorNome(nome);
		List<String> listaProdutos = new ArrayList<String>();
		for (Produto prod : produtos) {
			listaProdutos.add(prod.getNome());
		}
		return listaProdutos;
	}

	public void buscarPorFiltros() {
		setEntidades(getMovimentancaoService().buscarPorFiltros(getFormulario().getFiltroDataMovimentacao(),
				getFormulario().getFiltroNomeProduto(), getFormulario().getFiltroStatusMovimentacao(),
				getFormulario().getFiltroNumeroNota(), getFormulario().getFiltroFilial()));

	}

	public void salvarAlterarDetalhes() {
		for (MovimentacaoProduto movProd : getEntidade().getMovimentacoesProduto()) {
			if (movProd.getProduto().getCEAN() != null
					&& getFormulario().getProdutoAlterar().getProduto().getCEAN() != null
					&& movProd.getProduto().getCEAN()
							.equals(getFormulario().getProdutoAlterar().getProduto().getCEAN())) {
				carregarMP(movProd, getFormulario().getProdutoAlterar());
			}
		}
		somarValores();

	}

	public void carregarAlterarDetalhes() {
		getFormulario().setProdutoAlterar(new MovimentacaoProduto());

		carregarMP(getFormulario().getProdutoAlterar(), getFormulario().getMpSelecionado());

	}

	private void carregarMP(MovimentacaoProduto produtoCarregar, MovimentacaoProduto produtoCarregado) {
		produtoCarregar.setProduto(produtoCarregado.getProduto());
		produtoCarregar.setId(produtoCarregado.getId());
		produtoCarregar.setLucro(produtoCarregado.getLucro());
		produtoCarregar.setMovimentacaoEstoque(produtoCarregado.getMovimentacaoEstoque());
		produtoCarregar.setQtCom(produtoCarregado.getQtCom());
		produtoCarregar.setQtTrib(produtoCarregado.getQtTrib());
		produtoCarregar.setStatusMovimentacao(produtoCarregado.getStatusMovimentacao());
		produtoCarregar.setTipoMovimentacao(produtoCarregado.getTipoMovimentacao());
		produtoCarregar.setUnCom(produtoCarregado.getUnCom());
		produtoCarregar.setUnTrib(produtoCarregado.getUnTrib());
		produtoCarregar.setValorProduto(produtoCarregado.getValorProduto());
		produtoCarregar.setValorFrete(produtoCarregado.getValorFrete());
		produtoCarregar.setValorSeguro(produtoCarregado.getValorSeguro());
		produtoCarregar.setValorDesconto(produtoCarregado.getValorDesconto());
		produtoCarregar.setValorDespesas(produtoCarregado.getValorDespesas());
		produtoCarregar.setValorUnCom(produtoCarregado.getValorUnCom());
		produtoCarregar.setValorUnTrib(produtoCarregado.getValorUnTrib());

	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	public void imprimirEtiquetas() throws IOException {
		ServletOutputStream ouputStream = null;

		JRBeanCollectionDataSource lista = new JRBeanCollectionDataSource(getEntidade().getMovimentacoesProduto());

		HashMap parameters = new HashMap();
		parameters.put("teste", "teste");

		try {

			FacesContext facesContext = FacesContext.getCurrentInstance();

			facesContext.responseComplete();

			ServletContext scontext = (ServletContext) facesContext.getExternalContext().getContext();

			JasperPrint jasperPrint = JasperFillManager.fillReport(
					scontext.getRealPath("/paginas/modEstoque/venda/etiqueta.jasper"), parameters, lista);

			ByteArrayOutputStream baos = new ByteArrayOutputStream();

			JRPdfExporter exporter = new JRPdfExporter();

			exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);

			exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, baos);

			exporter.exportReport();

			byte[] bytes = baos.toByteArray();

			if (bytes != null && bytes.length > 0) {

				HttpServletResponse response = (HttpServletResponse) facesContext.getExternalContext().getResponse();

				response.setContentType("application/pdf");

				response.setHeader("Content-disposition", "inline; filename=\"relatorioPorData.pdf\"");

				response.setContentLength(bytes.length);

				ServletOutputStream outputStream = response.getOutputStream();

				outputStream.write(bytes, 0, bytes.length);

				outputStream.flush();

				outputStream.close();
			}

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (ouputStream != null)
				ouputStream.close();

		}
	}

	public List<String> autoCompleteNomeFornecedor(String nome) {
		Collection<Pessoa> fornecedores = getMovimentancaoService().listarFornecedorPorNome(nome);
		List<String> listaEntidades = new ArrayList<String>();
		for (EntidadeManter e : fornecedores) {
			listaEntidades.add(e.getNome());
		}
		return listaEntidades;

	}

	public List<String> autoCompleteNomeTransportador(String nome) {
		Collection<Pessoa> fornecedores = getMovimentancaoService().listarTransportadorPorNome(nome);
		List<String> listaEntidades = new ArrayList<String>();
		for (EntidadeManter e : fornecedores) {
			listaEntidades.add(e.getNome());
		}
		return listaEntidades;

	}

	public void buscarFornecedorPorFiltros() {
		getFiltro().setTipoPessoa(getMovimentancaoService().buscarTipoPessoaPorNome(TipoPessoaEnum.FORNECEDOR.getLabel()));
		getFormulario().setFornecedorSelecionar(
				new PessoaDataModel(getMovimentancaoService().listarPessoaPorFiltro(getFiltro())));
	}

	public void buscarTransportadorPorFiltros() {
		getFiltro().setTipoPessoa(
				getMovimentancaoService().buscarTipoPessoaPorNome(TipoPessoaEnum.TRANSPORTADOR.getLabel()));
		getFormulario().setTransportadorSelecionar(
				new PessoaDataModel(getMovimentancaoService().listarPessoaPorFiltro(getFiltro())));
	}

	public void adicionarFornecedor() {
		getFormulario().setFornecedorSelecionar(new PessoaDataModel(new ArrayList<Pessoa>()));
	}

	public void adicionarTransportador() {
		getFormulario().setTransportadorSelecionar(new PessoaDataModel(new ArrayList<Pessoa>()));

	}

}
